package com.gztms.travelmgnt.service.impl;

import com.aliyuncs.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gztms.enums.OrderStatus;
import com.gztms.ordermgnt.pojo.Order;
import com.gztms.ordermgnt.service.OrderService;
import com.gztms.travelmgnt.mapper.AreaMapper;
import com.gztms.travelmgnt.mapper.AttrCateMapper;
import com.gztms.travelmgnt.mapper.AttractionsMapper;
import com.gztms.travelmgnt.pojo.Area;
import com.gztms.travelmgnt.pojo.AttrCate;
import com.gztms.travelmgnt.pojo.Attractions;
import com.gztms.travelmgnt.pojo.vo.Attraction;
import com.gztms.travelmgnt.pojo.vo.AttractionVO;
import com.gztms.travelmgnt.service.AttractionsService;
import com.gztms.usermgnt.pojo.User;
import com.gztms.usermgnt.service.UserService;
import com.gztms.utils.BeanCopyUtils;
import com.gztms.utils.ResultUtil;
import com.gztms.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Attr;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Zoey
 * @date 2023/4/19 21:04
 * @Description TODO
 **/
@Service
public class AttractionsServiceImpl extends ServiceImpl<AttractionsMapper,Attractions> implements AttractionsService {
    @Autowired
    private AttractionsMapper attractionsMapper;
    @Autowired
    private AreaMapper areaMapper;
    @Autowired
    private AttrCateMapper attrCateMapper;
    @Autowired
    private UserService userService;
    @Autowired
    private OrderService orderService;



    /**
     * 添加新景区
     * @param attractions
     * @return
     */
    @Override
    public ResultUtil addAttr(Attractions attractions) {
        attractions.setRemainSum(attractions.getLimitPerson());

        // TODO
        boolean save = save(attractions);
        if (save) {
            return new ResultUtil(ResultUtil.SUCCESS, "添加景区成功");
        }
        return new ResultUtil(ResultUtil.SERVER_ERROR,"添加景区失败");
    }

    /**
     * 查询景区
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public ResultUtil findAttrs(int pageNum, int pageSize) {
        Page<Attractions> attractionsPage = new Page(pageNum,pageSize);
        attractionsMapper.selectPage(attractionsPage, null);
        List<Attractions> records = attractionsPage.getRecords();
        Map<String, Object> map = new HashMap<>();
        map.put("attractions",records);
        map.put("pageSum",attractionsPage.getPages());
        map.put("total", attractionsPage.getTotal());
        return new ResultUtil(ResultUtil.SUCCESS,"景区查询成功",map);
    }

    /**
     * 查询所有地区
     * @return
     */
    @Override
    public ResultUtil findAllArea() {
        List<Area> areas = areaMapper.selectList(null);
        Map<String,Object> map = new HashMap<>();
        map.put("areas",areas);
        return new ResultUtil(ResultUtil.SUCCESS,"地区查询成功", map);
    }

    /**
     * 查询所有景区类别
     * @return
     */
    @Override
    public ResultUtil findAllCate() {
        List<AttrCate> attrCates = attrCateMapper.selectList(null);
        Map<String,List<AttrCate>> map = new HashMap<>();
        map.put("attrTypes",attrCates);
        return new ResultUtil(ResultUtil.SUCCESS,"地区查询成功", map);
    }

    @Override
    public ResultUtil updateAttr(Attractions attractions) {
        int result = attractionsMapper.updateById(attractions);
        if (result == 1) {
            return new ResultUtil(ResultUtil.SUCCESS, "景区修改成功");
        }
        return new ResultUtil(ResultUtil.SERVER_ERROR,"景区修改失败");
    }

    @Override
    public ResultUtil updateAttrBanner(String bannerUrl) {
        Map<String, Object> map = new HashMap<>();
        if (StringUtils.isEmpty(bannerUrl)) {
            return new ResultUtil(ResultUtil.SERVER_ERROR,"图片上传失败");
        }
        map.put("bannerUrl", bannerUrl);
        return new ResultUtil(ResultUtil.SUCCESS,"图片上传成功",map);
    }

    @Override
    public ResultUtil addAttrCate(AttrCate attrCate) {

        int result = attrCateMapper.insert(attrCate);
        if (result == 1) {
            return new ResultUtil(ResultUtil.SUCCESS, "添加景区类别成功");
        }
        return new ResultUtil(ResultUtil.SERVER_ERROR,"添加景区类别失败");
    }

    @Override
    public ResultUtil updateAttrCate(AttrCate attrCate) {
        int result = attrCateMapper.updateById(attrCate);
        if (result == 1) {
            return new ResultUtil(ResultUtil.SUCCESS, "景区类别修改成功");
        }
        return new ResultUtil(ResultUtil.SERVER_ERROR,"景区类别修改失败");
    }

    @Override
    public ResultUtil delAttrById(Integer attrId) {
        int result = attractionsMapper.deleteById(attrId);
        if (result == 1) {
            return new ResultUtil(ResultUtil.SUCCESS, "景区删除成功");
        }
        return new ResultUtil(ResultUtil.SERVER_ERROR,"景区删除失败");
    }

    @Override
    public ResultUtil findAttrById(Integer attrId) {
        Attractions attraction = getById(attrId);
        if (Objects.isNull(attraction)) {
            return new ResultUtil(ResultUtil.SERVER_ERROR, "景区不存在");
        }
        // 封装数据
        AttractionVO attractionVO = BeanCopyUtils.copyBean(attraction, AttractionVO.class);
        String areaName = areaMapper.selectById(attractionVO.getAreaId()).getAreaName();
        attractionVO.setAreaName(areaName);
        String cateName = attrCateMapper.selectById(attractionVO.getAttrCateId()).getCateName();
        attractionVO.setCateName(cateName);

        Map<String,Object> map = new HashMap<>();
        map.put("attraction", attractionVO);
        return new ResultUtil(ResultUtil.SUCCESS,"景区查询成功", map);
    }

    @Override
    public ResultUtil searchAttrList(Integer pageNum, Integer pageSize, String name, Integer attrCateId, Integer areaId) {
        Page<Attractions> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<Attractions> queryWrapper = new LambdaQueryWrapper();
        if (org.springframework.util.StringUtils.hasText(name)) {
            queryWrapper.like(Attractions::getName, name);
        }
        if (Objects.nonNull(attrCateId) && attrCateId != 0) {
            queryWrapper.eq(Attractions::getAttrCateId, attrCateId);
        }

        if (Objects.nonNull(areaId) && areaId != 12) {
            queryWrapper.eq(Attractions::getAreaId,areaId);
        }


        Page<Attractions> attractionsPage = page(page, queryWrapper);
        // 封装数据
        List<Attractions> attractions = attractionsPage.getRecords();
        List<AttractionVO> attractionVOS = BeanCopyUtils.copyBeanList(attractions, AttractionVO.class);
        attractionVOS.stream()
                .map(attractionVO -> {
                    String areaName = areaMapper.selectById(attractionVO.getAreaId()).getAreaName();
                    attractionVO.setAreaName(areaName);
                    String cateName = attrCateMapper.selectById(attractionVO.getAttrCateId()).getCateName();
                    attractionVO.setCateName(cateName);
                    return attractionVO;
                })
                .collect(Collectors.toList());
        Map<String,Object> map = new HashMap<>();
        map.put("attractions",attractionVOS);
        map.put("total",attractionsPage.getTotal());
        return new ResultUtil(ResultUtil.SUCCESS,"查询成功",map);

    }

    @Override
    public ResultUtil recommendAttr() {
        String uid = SecurityUtils.getUid();
        List<Attractions> attractionsList = recommendAttr(uid);
//        List<AttractionVO> attractionVOS;
        // 处理数据
        List<Attraction> attractions = BeanCopyUtils.copyBeanList(attractionsList, Attraction.class);
        List<Attraction> collect = attractions.stream()
                .map(attraction -> {
                    attraction.setAreaName(areaMapper.selectById(attraction.getAreaId()).getAreaName());
                    attraction.setCateName(attrCateMapper.selectById(attraction.getAttrCateId()).getCateName());
                    return attraction;
                })
                .collect(Collectors.toList());

//        Collections.sort(collect, new Comparator<Attraction>() {
//            @Override
//            public int compare(Attraction o1, Attraction o2) {
//                return (int) (o2.getW()-o1.getW());
//            }
//        });
        collect.forEach(p->{
            System.out.println(p);
        });
        Map<String,Object> map = new HashMap<>();
        map.put("recommendAttrs",collect);

        return ResultUtil.okResult(map);
    }

    private   List<Attractions> recommendAttr(String uid) {
        List<Order> orderList = new ArrayList<>();  // 当前用户的所有订单

        List<User> userList = userService.list();   //  所有用户
        List<Attractions> attractionsList = list();  // 所有景区

//        List<Order>

        int[][] curMatrix = new int[attractionsList.size()+5][attractionsList.size()+5];   //当前矩阵
        int[][] comMatrix = new int[attractionsList.size()+5][attractionsList.size()+5];   //共现矩阵
        int[] N = new int[attractionsList.size()+5];                              //购买每个景区门票的人数

        for (User user : userList) {
            if (user.getUid()==uid) {
                continue;
            }

            // 查询当前用户的所有订单
            LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Order::getCreatedBy, uid);
            queryWrapper.eq(Order::getStatus, OrderStatus.ORDER_PAID);
            orderList = orderService.list(queryWrapper);

            // 清空矩阵
            for (int i = 0; i < attractionsList.size(); i++) {
                for (int j = 0; j < attractionsList.size(); j++) {
                    curMatrix[i][j] = 0;
                }
            }
            //
            for(int i = 0; i < orderList.size(); i++){
                int attrId = orderList.get(i).getAttrId();
                ++N[attrId];
                for(int j = i+1; j < orderList.size(); j++){
                    int attrId2 = orderList.get(j).getAttrId();
                    ++curMatrix[attrId][attrId2];
                    ++curMatrix[attrId2][attrId]; //两两加一
                }
            }

            //累加所有矩阵, 得到共现矩阵
            for(int i = 0; i < attractionsList.size(); i++){
                for(int j = 0; j < attractionsList.size(); j++){
                    int pid1 = attractionsList.get(i).getAttrId(), pid2 = attractionsList.get(j).getAttrId();
                    comMatrix[pid1][pid2] += curMatrix[pid1][pid2];
                    comMatrix[pid1][pid2] += curMatrix[pid1][pid2];
                }
            }

        }

        TreeSet<Attractions> preList = new TreeSet<Attractions>(new Comparator<Attractions>() {

            @Override
            public int compare(Attractions o1, Attractions o2) {
                if (o1.getW()!=o2.getW()) {
                    return (int) (o1.getW()-o2.getW())*100;
                }

                return o1.getLimitPerson()-o1.getRemainSum() - (o2.getLimitPerson()-o2.getRemainSum());
            }
        }); //预处理的列表

        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Order::getCreatedBy, uid);
        queryWrapper.eq(Order::getStatus, OrderStatus.ORDER_PAID);
        orderList = orderService.list(queryWrapper);    //  获取当店用户的订单列表
        boolean[] used = new boolean[attractionsList.size()+5]; // 判重数组
        // 遍历订单列表
        for (Order order : orderList) {
            int Nij = 0;                          // 既购买了A又购买了B景区的人
            double Wij;                           // 相似度
            Attractions tmp;                      // 景区

            int i = order.getAttrId();          // 获取景区编号
            // 遍历景区
            for (Attractions attraction : attractionsList) {
                if (order.getAttrId() == attraction.getAttrId()) {
                    continue;
                }
                int j = attraction.getAttrId();
                Nij = comMatrix[i][j];
                Wij = (double)Nij/Math.sqrt(N[i]*N[j]); //计算余弦相似度

                // 设置景区相似度
                tmp = getById(attraction.getAttrId());
                tmp.setW(Wij);

                if (used[tmp.getAttrId()]) continue;
                preList.add(tmp);
                used[tmp.getAttrId()] = true;
            }
        }

        // 生成推荐结果
        ArrayList<Attractions> collect = new ArrayList<>();
        List<Attractions> recomLists = new ArrayList<>();
        for(int i = 0; preList.size()>0 && i<5; i++){
            recomLists.add(preList.pollLast());
            preList.pollLast();
        }
        if(recomLists.size()<5){
            //推荐数量不满5个, 补足最受欢迎的景区
            LambdaQueryWrapper<Attractions> wrapper = new LambdaQueryWrapper<>();
            wrapper.orderByAsc(Attractions::getRemainSum);
            LambdaQueryWrapper<Order> orderWrapper = new LambdaQueryWrapper<>();
            orderWrapper.ne(Order::getCreatedBy,uid);
            List<Order> orders = orderService.list(orderWrapper);
            List<Integer> uids = new ArrayList<>();
            for (Order order : orders) {
                uids.add(order.getAttrId());
            }
            Page<Attractions> page = new Page<>(1,10);
            for (Integer integer : uids) {
                wrapper.ne(Attractions::getAttrId, integer);
            }
            //            queryWrapper.ne()
            List<Attractions> list = page(page,wrapper).getRecords();
            System.out.println(recomLists);
            int j = 0;
//            recomLists.addAll(list);
//            for (int i = recomLists.size(); i < 10; i++) {
//                // TODO 这里不能直接加，会有重复
////                Attractions temp;
//                recomLists.add(list.get(j));
//                j++;
//            }

            list.forEach(p->{
                boolean flag = recomLists.stream().anyMatch(attractions -> attractions.getAttrId().equals(p.getAttrId()));
                if (!flag) {
                    recomLists.add(p);
                }
                if (recomLists.size()==5) return;

            });
            return recomLists.subList(0,5);
            // 去重
//            collect = recomLists.stream()
//                    .collect(Collectors.collectingAndThen(
//                            Collectors.toCollection(
//                                    () -> new TreeSet<Attractions>(Comparator.comparing(Attractions::getAttrId))), ArrayList::new));

//            recomLists = attractionsService.list(wrapper);
        }
        return recomLists;
    }
}
